package com.sneakxy.mybase4j.platform.service;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.csource.common.MyException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.dubbo.config.annotation.Reference;
import com.sneakxy.mybase4j.base.fastdfs.FastDfsClient;
import com.sneakxy.mybase4j.base.service.BaseService;
import com.sneakxy.mybase4j.platform.beans.UEditor;
import com.sneakxy.mybase4j.platform.provider.IUEditorProvider;
import com.sneakxy.mybase4j.shiro.bean.ShiroAccount;
import com.sneakxy.mybatis.commons.repository.query.domain.CriteriaBuilder;

import sun.misc.BASE64Decoder;

/**
 * 
 * @author 潜行的青衣
 * @see
 */
@SuppressWarnings("restriction")
@Service
public class UEditorService extends BaseService<UEditor, String, IUEditorProvider> implements IUEditorService {
	
	@Value("${ueditor.storage.type}")
	private String ueditorStorageType;
	
	@Value("${ueditor.storage.local}")
	private String ueditorStorageLocal;

	@Reference(version = "1.0.0")
	@Autowired(required = false)
	@Qualifier("UEditorProvider")
	private IUEditorProvider provider;

	@Resource
	private FastDfsClient fastDfsClient;
	
	@Override
	public IUEditorProvider getProvider() {
		return this.provider;
	}

	@Override
	public Map<String, Object> findAll(String type, String account, int start, int size) {
		CriteriaBuilder<UEditor> builder = new CriteriaBuilder<UEditor>(UEditor.class);
		if(StringUtils.isBlank(account)) {
			builder.andIsNull("account");
		} else {
			builder.andEq("account", account);
		}
		builder.andEq("type", type);
		
		int page = start / size;
		Page<UEditor> pager = this.findAll(builder.build(), new PageRequest(page, size, new Sort("createtime")));
		
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		Iterator<UEditor> it = pager.iterator();
		while(it.hasNext()) {
			list.add(it.next().toMap());
		}
		Map<String, Object> result = new LinkedHashMap<String, Object>();
		result.put("state", "SUCCESS");
		result.put("list", list);
		result.put("start", start);
		result.put("total", pager.getTotalElements());
		return result;
	}

	@Override
	public UEditor findOne(String id, String type) {
		CriteriaBuilder<UEditor> builder = new CriteriaBuilder<UEditor>(UEditor.class);
		builder.andEq("id", id);
		builder.andEq("type", type);
		return this.findOne(builder.build());
	}
	
	@Override
	public UEditor uploadAndSave(HttpServletRequest request, MultipartFile file, String type) throws IOException, MyException {
		ShiroAccount loginAccount = (ShiroAccount) SecurityUtils.getSubject().getPrincipal();
		String account = loginAccount != null ? loginAccount.getAccount() : null;
		String filepath = null;
		if(StringUtils.equalsIgnoreCase(this.ueditorStorageType, UEditor.STORAGE_FASTDFS)) {
			filepath = this.fastDfsClient.uploadFile(file.getInputStream(), file.getSize(), "");
		} else if(StringUtils.equalsIgnoreCase(this.ueditorStorageType, UEditor.STORAGE_LOCAL)) {
			filepath = this.uploadToLocal(request, file.getInputStream(), type);
		} else {
			throw new UnsupportedOperationException("暂时未实现其他保存方式");
		}
		UEditor ueditor = UEditor.newInstance(file);
		ueditor.setAccount(account);
		ueditor.setType(type);
		ueditor.setStorage(this.ueditorStorageType);
		ueditor.setFilepath(filepath);
		return this.save(ueditor);
	}

	@Override
	public UEditor uploadAndSave(HttpServletRequest request, String base64, String filename) throws IOException, MyException {
		ShiroAccount loginAccount = (ShiroAccount) SecurityUtils.getSubject().getPrincipal();
		String account = loginAccount != null ? loginAccount.getAccount() : null;
		//图片处理
		BASE64Decoder decoder = new BASE64Decoder();  
		byte[] buffer = decoder.decodeBuffer(base64);
		
		ByteArrayInputStream imageIO = new ByteArrayInputStream(buffer);
		
		String filepath = null;
		if(StringUtils.equalsIgnoreCase(this.ueditorStorageType, UEditor.STORAGE_FASTDFS)) {
			filepath = this.fastDfsClient.uploadFile(imageIO, buffer.length, "");
		} else if(StringUtils.equalsIgnoreCase(this.ueditorStorageType, UEditor.STORAGE_LOCAL)) {
			filepath = this.uploadToLocal(request, imageIO, UEditor.TYPE_IMAGE);
		} else {
			throw new UnsupportedOperationException("暂时未实现其他保存方式");
		}
		UEditor ueditor = new UEditor();
		ueditor.setAccount(account);
		ueditor.setContentSize(new Long(buffer.length));
		ueditor.setContentType("image/jpeg");
		ueditor.setFilename(filename);
		ueditor.setCreatetime(DateFormatUtils.format(Calendar.getInstance(), "yyyy-MM-dd HH:mm:ss"));
		ueditor.setType(UEditor.TYPE_IMAGE);
		ueditor.setStorage(this.ueditorStorageType);
		ueditor.setFilepath(filepath);
		return this.save(ueditor);
	}
	
	public String uploadToLocal(HttpServletRequest request, InputStream is, String type) throws FileNotFoundException, IOException {
		StringBuilder path = new StringBuilder();
		if(StringUtils.isBlank(this.ueditorStorageLocal)) {
			path.append(request.getServletContext().getRealPath("/upload/"));
		} else {
			path.append(this.ueditorStorageLocal);
		}
		if(!StringUtils.equals(File.separator, path.substring(path.length() - 1))) {
			path.append(File.separator);
		}
		File dir = new File(path.toString());
		if(!dir.exists()) {
			dir.mkdirs();
		}
		path.append(DateFormatUtils.format(Calendar.getInstance(), "yyyyMMddHHmmss"));
		path.append("-").append(RandomStringUtils.random(4, true, true));
		String result = path.toString();
		
		OutputStream os = null;
		try {
			os = new FileOutputStream(result);
			IOUtils.copy(is, os);
		} finally {
			IOUtils.closeQuietly(os);
		}
		return result;
	}
	
	@Override
	public void download(HttpServletResponse response, String id, String type) throws IOException, MyException {
		UEditor ueditor = this.findOne(id, type);
		if(ueditor != null) {
			response.setContentType(ueditor.getContentType());
			response.setContentLength(ueditor.getContentSize().intValue());
			response.addHeader("Content-Disposition", "attachment;filename=" + java.net.URLEncoder.encode(ueditor.getFilename(), "UTF-8"));
			if(StringUtils.equals(UEditor.STORAGE_FASTDFS, ueditor.getStorage())) {
				this.fastDfsClient.downloadFile(ueditor.getFilepath(), response.getOutputStream());
			} else if(StringUtils.equals(UEditor.STORAGE_LOCAL, ueditor.getStorage())) {
				OutputStream os = null;
				try {
					os = response.getOutputStream();
					FileUtils.copyFile(new File(ueditor.getFilepath()), os);
				} finally {
					IOUtils.closeQuietly(os);
				}
			} else {
				throw new UnsupportedOperationException("暂时不支持其他存储方式");
			}
		}
	}

}
